/***************************************************************************
 *   This is a part of the AMCAX Web CAD.                                  *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/
import { Vector3 } from 'three';
import { Constants } from '../common/Constants';
import { cmdMgr } from '../manager/CmdManager';
import { docMgr } from '../manager/DocumentManager';
import { ctx2 } from '../module';

export const wsApi = {
  getEngine: () => {
    return ctx2.get(Constants.CORE_ENGINE);
  },

  // start Transaction
  startTransaction: async (params?: any) => {
    return await wsApi
      .getEngine()
      .execCmd({ c: 'StartTransaction', ...params });
  },
  setArguments: async (params?: any) => {
    return await wsApi.getEngine().execCmd({ c: 'SetArguments', ...params });
  },
  executeTransaction: async (params?: any) => {
    try {
      const data: any = await wsApi
        .getEngine()
        .execCmd({ c: 'ExecuteTransaction', ...params });
      if (data) {
        // 成功的情况，返回处理后的数据
        return data;
      } else {
        // 错误或异常情况，抛出错误
        console.log(`Transaction failed with nio data`);
        throw new Error(`Transaction failed with no data`);
      }
    } catch (error) {
      console.error('Error in executeTransaction:', error);
      throw error; // 将错误向上抛出
    }
  },
  endTransaction: async (params?: any) => {
    await wsApi.getEngine().execCmd({ c: 'EndTransaction', ...params });
    cmdMgr.increaseUndo();
  },
  abortTransaction: async (params?: any) => {
    return await wsApi
      .getEngine()
      .execCmd({ c: 'AbortTransaction', ...params });
  },
  // end Transaction

  getObjects: async (dxids?: string[]): Promise<any> => {
    const cmd: {
      c: string;
      o: string[] | undefined;
    } = { c: 'GetObjects', o: undefined };
    if (dxids) cmd.o = dxids;
    return wsApi.getEngine().execCmd(cmd);
  },
  getVisualData: async (dxids?: string[]): Promise<any> => {
    const cmd: {
      c: string;
      o: string[] | undefined;
    } = { c: 'GetVisualData2', o: undefined };
    if (dxids) cmd.o = dxids;
    try {
      const result = await wsApi.getEngine().execCmd(cmd);
      return result;
    } catch (e) {
      console.log('getVisualData[e]', e);
    }
  },
  openNextModel: async (path: string) => {
    return await wsApi.getEngine().execCmd({ c: 'OpenNextModel', t: path });
  },
  openDocument: async (version: string | number, readonly: boolean) => {
    return await wsApi
      .getEngine()
      .execCmd({ c: 'OpenDocument', readonly, version });
  },
  getDocumentProperties: async () => {
    const cmd = {
      c: 'GetObjectProperty',
    };
    const res = await wsApi.getEngine().execCmd(cmd);
    return res.Document;
  },
  getDocumentMaterials: async (): Promise<any[]> => {
    const cmd = {
      c: 'GetMaterials',
    };
    const res = await wsApi.getEngine().execCmd(cmd);
    return res.Materials ? res.Materials : [];
  },
  clearUndo: async () => {
    return wsApi.getEngine().execCmd({ c: 'ClearUndo' });
  },
  undo: async () => {
    return wsApi.getEngine().execCmd({ c: 'Undo' });
  },
  redo: async () => {
    return wsApi.getEngine().execCmd({ c: 'Redo' });
  },

  delete(dxid: string | string[]) {
    const result = wsApi.getEngine().execCmd({ c: 'Delete', o: dxid });
    // cmdMgr.increaseUndo()
    cmdMgr.increaseUndo();
    return result;
  },
  copy: async (params?: any) => {
    const result = await wsApi.getEngine().execCmd({ c: 'Copy', ...params });
    cmdMgr.increaseUndo();
    return result;
  },
  makeEuclid: async (params?: any) => {
    const result = await wsApi
      .getEngine()
      .execCmd({ c: 'MakeEuclid', ...params });
    cmdMgr.increaseUndo();
    return result;
  },
  makeArray: async (
    dxid: string,
    count: number,
    direction: string,
    distance: number,
  ) => {
    const result = await wsApi
      .getEngine()
      .execCmd({ c: 'CreateArray', o: dxid, count, direction, distance });
    cmdMgr.increaseUndo();
    return result;
  },
  importModel: async (params?: any) => {
    return await wsApi.getEngine().execCmd({ c: 'ImportModel', ...params });
  },
  exportModel: async (params?: any) => {
    console.log('exportModel', params);
    return await wsApi.getEngine().execCmd({ c: 'ExportModel', ...params });
  },
  setTransform: async (params?: any) => {
    const result = await wsApi
      .getEngine()
      .execCmd({ c: 'SetTransform', ...params });
    cmdMgr.increaseUndo();
    return result;
  },

  // ====== 草图命令 ======
  createCurve: async (type: string, params: any) => {
    const result = wsApi
      .getEngine()
      .execCmd({ c: 'CreateCurve', type, a: params });
    cmdMgr.increaseUndo();
    return result;
  },
  createLine: async (point1: Vector3, point2: Vector3) => {
    return await wsApi.createCurve('Line', {
      point1: [point1.x, point1.y, point1.z],
      point2: [point2.x, point2.y, point2.z],
    });
  },
  createPolygon: async (points: Vector3[]) => {
    const _points = points.map((point: Vector3) => {
      return [point.x, point.y, point.z];
    });
    return await wsApi.createCurve('Polygon', {
      points: _points,
    });
  },
  createRectangle: async (points: Vector3[]) => {
    const _points = points.map((point: Vector3) => {
      return [point.x, point.y, point.z];
    });
    return await wsApi.createCurve('Polygon', {
      points: _points,
    });
  },
  createBspline: async (points: Vector3[]) => {
    const _points = points.map((point: Vector3) => {
      return [point.x, point.y, point.z];
    });
    return await wsApi.createCurve('Bspline', {
      points: _points,
    });
  },
  createCircle: async (
    center: Vector3,
    radius: number,
    placement: number[][],
  ) => {
    console.log('Circle', center, radius, placement);
    const result = await wsApi.createCurve('Circle', {
      center: [center.x, center.y, center.z],
      radius: radius,
      placement,
    });
    return result;
  },
  createEllipse: async (
    center: Vector3,
    major: number,
    minor: number,
    placement: number[][],
  ) => {
    console.log('Ellipse', center, major, minor, placement);
    return await wsApi.createCurve('Ellipse', {
      center: [center.x, center.y, center.z],
      major: major,
      minor: minor,
      placement,
    });
  },
  createArc: async (
    center: Vector3,
    point1: Vector3,
    point2: Vector3,
    placement: number[][],
  ) => {
    const result = await wsApi.createCurve('ArcOfCircle', {
      center: [center.x, center.y, center.z],
      point1: [point1.x, point1.y, point1.z],
      point2: [point2.x, point2.y, point2.z],
      placement,
    });
    return result;
  },
  createHelix: async (
    pitch: number,
    height: number,
    radius: number,
    angle: number,
    leftup: boolean,
  ) => {
    return await wsApi.createCurve('Helix', {
      pitch: pitch,
      height: height,
      radius: radius,
      angle: angle,
      leftup: leftup,
    });
  },
  // ====== 草图命令 ======

  createExtrude: async (
    dxids: string[],
    height: number,
    solid: boolean = true,
  ) => {
    const documents = docMgr.flatDocumentObjects;
    dxids.forEach(async (dxid) => {
      const document = documents.filter(
        (document) => document.dxid === dxid,
      )[0];
      const vector = new Vector3(
        document.placement[1][0],
        document.placement[1][1],
        document.placement[1][2],
      ).multiplyScalar(height);
      await wsApi.getEngine().execCmd({
        c: 'CreateExtrude',
        a: {
          profile: dxids,
          vector: [vector.x, vector.y, vector.z],
          solid: solid,
        },
      });
      cmdMgr.increaseUndo();
    });
  },

  // ====== 基本图形命令 ======
  createPrimitive: async (type: string, params: any, placement?: any) => {
    const cmd = { c: 'CreatePrimitive', type, a: params, placement: undefined };
    if (placement) cmd.placement = placement;
    const result = wsApi.getEngine().execCmd(cmd);
    cmdMgr.increaseUndo();
    // console.log('createPrimitive', result)
    // return wsApi.updateDocumentAndreadVisualData(result)
    return result;
  },
  createSphere: async (center: Vector3, radius: number) => {
    const result = await wsApi.createPrimitive(
      'Sphere',
      {
        radius: radius,
      },
      [
        [center.x, center.y, 0],
        [0, 0, 1],
        [1, 0, 0],
      ],
    );
    return result;
  },
  createTube: async (
    radius1: number,
    radius2: number,
    height: number,
    angle: number,
  ) => {
    const result = await wsApi.createPrimitive('Tube', {
      radius1: radius1,
      radius2: radius2,
      height: height,
      angle: angle,
    });
    return result;
  },
  createWedge: async (
    xmin: number,
    xmax: number,
    ymin: number,
    ymax: number,
    zmin: number,
    zmax: number,
    x2min: number,
    x2max: number,
    z2min: number,
    z2max: number,
  ) => {
    return await wsApi.createPrimitive('Wedge', {
      xmin: xmin,
      xmax: xmax,
      ymin: ymin,
      ymax: ymax,
      zmin: zmin,
      zmax: zmax,
      x2min: x2min,
      x2max: x2max,
      z2min: z2min,
      z2max: z2max,
    });
  },
  createPyramid: async (
    polygon: number,
    circumradius: number,
    height: number,
  ) => {
    return await wsApi.createPrimitive('Pyramid', {
      polygon: polygon,
      circumradius: circumradius,
      height: height,
    });
  },
  // ====== 基本图形命令 ======

  createCompound: async (dxids: string[]) => {
    return wsApi.getEngine().execCmd({
      c: 'CreateCompound',
      o: dxids,
    });
  },
  createSplit: async (dxid: string) => {
    return wsApi.getEngine().execCmd({
      c: 'CreateSplit',
      a: {
        base: dxid,
        tool: dxid,
      },
    });
  },

  createSweep: async (p_dxids: string[], s_dxids: string[]) => {
    return wsApi.getEngine().execCmd({
      c: 'CreateSweep',
      a: {
        profile: p_dxids,
        spine: s_dxids,
      },
    });
  },
  createRevolve: async (p_dxids: string[], point: Vector3, normal: Vector3) => {
    return wsApi.getEngine().execCmd({
      c: 'CreateRevol',
      a: {
        profile: p_dxids,
        axis: [
          [point.x, point.y, point.z],
          [normal.x, normal.y, normal.z],
        ],
      },
    });
  },
  async setLabel(dxid: string, label: string) {
    return await wsApi
      .getEngine()
      .execCmd({ c: 'SetLabel', o: dxid, l: label });
  },
  async setParams(dxid: string, params?: any) {
    return await wsApi
      .getEngine()
      .execCmd({ c: 'SetParams', o: dxid, a: params || {} });
  },
  async setPlacement(
    dxid: string,
    pos: number[],
    norm: number[],
    xdir: number[],
  ) {
    return await wsApi
      .getEngine()
      .execCmd({ c: 'SetPlacement', o: dxid, placement: [pos, norm, xdir] });
  },

  // 设置颜色
  /**
   * @param dxid 要设置颜色的对象
   * @param color 颜色
   * @param faceIndex 面索引，-1表示所有面
   */
  async setColor(dxid: string, color: string, faceIndex: number = -1) {
    return await wsApi.getEngine().execCmd({
      c: 'SetColor',
      o: dxid,
      a: {
        face: faceIndex,
        color: color,
      },
    });
  },

  // 设置是否可视
  async setVisible(dxid: string, visible: boolean) {
    return await wsApi.getEngine().execCmd({
      c: 'SetVisibility',
      o: dxid,
      visible: visible,
      recursive: false,
    });
  },

  // 属性 Properly
  getProperty: async () => {
    return await wsApi.getEngine().execCmd({ c: 'GetProperty' });
  },

  // 材质
  // 添加一种材质
  async addMaterial(material: any) {
    return await wsApi.getEngine().execCmd({
      c: 'AddMaterial',
      a: material,
    });
  },

  // undo redo
  async getUndoSize() {
    return await wsApi.getEngine().execCmd({ c: 'GetUndoSize' });
  },
  // async updateDocumentAndreadVisualData(data: any) {
  //   const { objects } = await wsApi.getObjects()
  //   // ctx2.setDocumentObjects(objects)
  //   docMgr.documentObjects = objects
  //   return ctx2.modelRender.readVisualData(data)
  // },

  // ====== 材质接口 ======
  async addMaterials() {
    const params = {
      color: '', // 可以没有
      texture: '', // 可以为空或没有
      ambient: '', // 可以没有
      diffuse: '', // 可以没有
      emissive: '', // 可以没有
      specular: '', // 可以没有
      shininess: 0.2, // double, 可以没有
      transparency: 0.0, // double, 可以没有
    };
    return await wsApi.getEngine().execCmd({ c: 'AddMaterial', a: params });
  },
  async editMaterials(material: any) {
    const params = Object.assign({}, material);
    if (params.dxid) delete params.dxid;
    if (params.faceIndex) delete params.faceIndex;
    return await wsApi.getEngine().execCmd({ c: 'EditMaterial', a: params });
  },
  async deleteMaterials(id: number) {
    return await wsApi.getEngine().execCmd({ c: 'DeleteMaterial', id });
  },
  /**
   * 给模型设置材质
   * face = -1 表示设置整体的材质 ; 从 0 开始
   * matId = -1 表示清除对应的材质
   */
  async setMaterials(dxid: string, faceIndex: number, materialId: number) {
    return await wsApi.getEngine().execCmd({
      c: 'SetMaterial',
      o: dxid,
      a: { face: faceIndex, matId: materialId },
    });
  },
  // ====== 材质接口 ======

  // ====== 电力行业命令 ======
  createPrimitiveELE: async (type: string, params: any) => {
    return await wsApi
      .getEngine()
      .execCmd({ c: 'CreatePrimitiveELE', type, a: params });
  },
  //绝缘子
  createInsulator: async (params: any) => {
    return wsApi.createPrimitiveELE('Insulator', params);
  },
  // 电杆横架
  createEleShelf: async (params: any) => {
    return wsApi.createPrimitiveELE('EleShelf', params);
  },
  // 直角板
  createAngleBoard: async (params: any) => {
    return wsApi.createPrimitiveELE('AngleBoard', params);
  },
  // 固定铁环
  createFixedHoop: async (params: any) => {
    return wsApi.createPrimitiveELE('FixedHoop', params);
  },
  //围栏
  createFence: async (params: any) => {
    return wsApi.createPrimitiveELE('Fence', params);
  },
  // 环网柜
  createRingCabinet: async (params: any) => {
    return wsApi.createPrimitiveELE('RingCabinet', params);
  },
  // 线缆
  createCable: async (spine: string, radius: number) => {
    return wsApi.createPrimitiveELE('Cable', { spine, radius });
  },
  // ====== 电力行业命令 ======

  // ====== BIM命令 ======
  createPrimitiveBIM: async (type: string, params: any) => {
    return await wsApi
      .getEngine()
      .execCmd({ c: 'CreatePrimitiveBIM', type, a: params });
  },
  createStep: async (params: any) => {
    // 总宽，总高，总长，阶数 , 默认值：300， 300， 360， 6
    // 每个台阶的高 = height / steps
    // 每个台阶的宽 = length / steps
    return wsApi.createPrimitiveBIM('SideStep', params);
  },
  createStair: async (params: any) => {
    return await wsApi.getEngine().execCmd({
      c: 'CreatePrimitiveBIM',
      type: 'Stairs',
      a: params,
      // startup: 左上，还是右上，值： left, right
      // 默认值： 250, 300, 10, left
    });
  },
  createLinearBlock: async (
    startPoint: number[],
    endPoint: number[],
    height: number,
    width: number,
  ) => {
    const result = await wsApi.createPrimitiveBIM('Wall', {
      segment: {
        point1: startPoint,
        point2: endPoint,
        height: height,
        thickness: width,
      },
    });
    return result;
  },
  // 获取洞口定位信息
  getHoleInfo: async (holeFaceId: string) => {
    console.log('getHoleInfo::', holeFaceId);
    return await wsApi
      .getEngine()
      .execCmd({ e: 'BIM', c: 'GetHoleInfo', o: holeFaceId });
  },
  // ====== BIM命令 ======

  // ====== 翼型设计 ======
  // App私有数据存储
  saveAppData: async (key: string, data: string) => {
    console.log('SaveAppData::', key, data);
    return await wsApi
      .getEngine()
      .execCmd({ c: 'SaveAppData', key: key, data: data });
  },
  // App私有数据获取
  getAppData: async (key: string) => {
    console.log('GetAppData::', key);
    return await wsApi.getEngine().execCmd({ c: 'GetAppData', key: key });
  },
  // 拟合曲线
  fitCurve: async (points: Vector3[]) => {
    const _points = points.map((point: Vector3) => {
      return [point.x, point.y, point.z];
    });
    const result = wsApi.getEngine().execCmd({
      c: 'CreateCurve',
      type: 'Bspline',
      a: {
        mode: 'Approx',
        points: _points,
      },
    });
    cmdMgr.increaseUndo();
    return result;
  },
  // ====== 翼型设计 ======
};
